/*            Copyright(c) 2006-2008 Dave Sexton           *
 * http://www.codeplex.com/DocProject                      *
 * http://www.codeplex.com/DocProject/Project/License.aspx *
 ***********************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using System.Collections.ObjectModel;

namespace DaveSexton.DocProject.DocSites
{
	public delegate void CombineAction<T>(T item, bool isDuplicate);

	[Flags]
	public enum CleanListOptions
	{
		None = 0, 

		TrimStart = 1, 
		TrimEnd = 2, 

		Trim = 3, 

		RemoveDuplicates = 4, 

		ToUpper = 8, 
		ToLower = 16
	}

	public static class ListHelper
	{
		public static IEnumerable<string> Clean(IEnumerable<string> list)
		{
			return Clean(list, CleanListOptions.None);
		}

		public static IEnumerable<string> Clean(IEnumerable<string> list, CleanListOptions options)
		{
			if (list == null)
				throw new ArgumentNullException("list");

			bool removeDuplicates = (options & CleanListOptions.RemoveDuplicates) == CleanListOptions.RemoveDuplicates;

			List<string> cleaned = (removeDuplicates) ? new List<string>() : null;

			foreach (string s in list)
			{
				string value = s;

				if ((options & CleanListOptions.Trim) == CleanListOptions.Trim)
					value = value.Trim();
				else if ((options & CleanListOptions.TrimStart) == CleanListOptions.TrimStart)
					value = value.TrimStart();
				else if ((options & CleanListOptions.TrimEnd) == CleanListOptions.TrimEnd)
					value = value.TrimEnd();

				if ((options & CleanListOptions.ToUpper) == CleanListOptions.ToUpper)
					value = value.ToUpper(System.Globalization.CultureInfo.CurrentCulture);
				else if ((options & CleanListOptions.ToLower) == CleanListOptions.ToLower)
					value = value.ToLower(System.Globalization.CultureInfo.CurrentCulture);

				if (removeDuplicates)
				{
					if (cleaned.Contains(value))
						continue;
					else
						cleaned.Add(value);
				}

				yield return value;
			}
		}

		public static IEnumerable<string> CleanAndSort(IEnumerable<string> list)
		{
			return CleanAndSort(list, CleanListOptions.None, StringComparer.CurrentCulture);
		}

		public static IEnumerable<string> CleanAndSort(IEnumerable<string> list, CleanListOptions options)
		{
			return CleanAndSort(list, options, StringComparer.CurrentCulture);
		}

		public static IEnumerable<string> CleanAndSort(IEnumerable<string> list, IComparer<string> comparer)
		{
			return CleanAndSort(list, CleanListOptions.None, comparer);
		}

		public static IEnumerable<string> CleanAndSort(IEnumerable<string> list, CleanListOptions options, IComparer<string> comparer)
		{
			if (list == null)
				throw new ArgumentNullException("list");

			List<string> cleaned = new List<string>(Clean(list, options));

			cleaned.Sort(comparer);

			return new ReadOnlyCollection<string>(cleaned);
		}

		public static IEnumerable<string> Parse(string list, char separator)
		{
			return Parse(list, separator, CleanListOptions.None);
		}

		public static IEnumerable<string> Parse(string list, char separator, CleanListOptions options)
		{
			if (list == null)
				throw new ArgumentNullException("list");

			return Clean(list.Split(new char[] { separator }, StringSplitOptions.RemoveEmptyEntries), options);
		}

		public static IEnumerable<string> ParseAndSort(string list, char separator)
		{
			return ParseAndSort(list, separator, CleanListOptions.None, StringComparer.CurrentCulture);
		}

		public static IEnumerable<string> ParseAndSort(string list, char separator, CleanListOptions options)
		{
			return ParseAndSort(list, separator, options, StringComparer.CurrentCulture);
		}

		public static IEnumerable<string> ParseAndSort(string list, char separator, IComparer<string> comparer)
		{
			return ParseAndSort(list, separator, CleanListOptions.None, comparer);
		}

		public static IEnumerable<string> ParseAndSort(string list, char separator, CleanListOptions options, IComparer<string> comparer)
		{
			if (list == null)
				throw new ArgumentNullException("list");

			return CleanAndSort(list.Split(new char[] { separator }, StringSplitOptions.RemoveEmptyEntries), options, comparer);
		}

		public static IDictionary<TKey, TValue> Union<TKey, TValue>(IDictionary<TKey, TValue> items1, IDictionary<TKey, TValue> items2, 
			IEqualityComparer<TKey> resultDictionaryComparer)
		{
			IDictionary<TKey, TValue> max = (items1.Count > items2.Count) ? items1 : items2;
			IDictionary<TKey, TValue> min = (max == items1) ? items2 : items1;
			IDictionary<TKey, TValue> result = new Dictionary<TKey, TValue>(max.Count, resultDictionaryComparer);

			foreach (KeyValuePair<TKey, TValue> item in min)
				if (max.ContainsKey(item.Key))
					result.Add(item);

			return result;
		}

		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")]
		public static IDictionary<TKey, TValue> Union<TKey, TValue>(IDictionary<TKey, TValue> items1, IDictionary<TKey, TValue> items2, 
			IEqualityComparer<TKey> resultDictionaryComparer, Action<KeyValuePair<TKey, TValue>> action)
		{
			if (action == null)
				throw new ArgumentNullException("action");

			IDictionary<TKey, TValue> max = (items1.Count > items2.Count) ? items1 : items2;
			IDictionary<TKey, TValue> min = (max == items1) ? items2 : items1;
			IDictionary<TKey, TValue> result = new Dictionary<TKey, TValue>(max.Count, resultDictionaryComparer);

			foreach (KeyValuePair<TKey, TValue> item in min)
			{
				if (max.ContainsKey(item.Key))
				{
					action(item);
					result.Add(item);
				}
			}

			return result;
		}

		public static IEnumerable<T> Union<T>(ICollection<T> items1, ICollection<T> items2)
		{
			ICollection<T> max = (items1.Count > items2.Count) ? items1 : items2;
			ICollection<T> min = (max == items1) ? items2 : items1;

			foreach (T item in min)
				if (max.Contains(item))
					yield return item;
		}

		public static IEnumerable<T> Union<T>(ICollection<T> items1, ICollection<T> items2, Action<T> action)
		{
			if (action == null)
				throw new ArgumentNullException("action");

			ICollection<T> max = (items1.Count > items2.Count) ? items1 : items2;
			ICollection<T> min = (max == items1) ? items2 : items1;

			foreach (T item in min)
			{
				if (max.Contains(item))
				{
					action(item);
					yield return item;
				}
			}
		}

		public static IEnumerable<T> Combine<T>(ICollection<T> items1, ICollection<T> items2, CombineAction<T> action)
		{
			if (action == null)
				throw new ArgumentNullException("action");

			ICollection<T> max = (items1.Count > items2.Count) ? items1 : items2;
			ICollection<T> min = (max == items1) ? items2 : items1;

			foreach (T item in min)
			{
				action(item, max.Contains(item));
				yield return item;
			}

			foreach (T item in max)
			{
				if (!min.Contains(item))
				{
					action(item, false);
					yield return item;
				}
			}
		}

		internal static StringList ParseStringList(string list, char separator, CleanListOptions options)
		{
			if (list == null)
				throw new ArgumentNullException("list");

			return new StringList(Clean(list.Split(new char[] { separator }, StringSplitOptions.RemoveEmptyEntries), options));
		}
	}
}
